package ptij.ADSL.de.ATUR;

import ptolemy.kernel.*;
import ptolemy.kernel.util.*;
import ptolemy.data.*;
import ptolemy.data.expr.*;
import ptolemy.data.type.*;
import ptolemy.actor.*;

import ptij.ADSL.common.MuxDataFrame;

import java.io.*;
import java.util.LinkedList;

//////////////////////////////////////////////////////////////////////////
//// MuxSyncTx
/**

@author Ivan Jeukens
*/
public class MuxSyncTx extends TypedAtomicActor {
           
    public MuxSyncTx(CompositeEntity container, String name) throws
            NameDuplicationException, IllegalActionException {
        super(container, name);

        start = new TypedIOPort(this, "start", true, false);
	start.setTypeEquals(BaseType.BOOLEAN);
    
	dataTx = new TypedIOPort(this, "dataTx", true, false);
	dataTx.setTypeEquals(BaseType.INT);

	LS0 = new TypedIOPort(this, "LS0", true, false);
	LS0.setTypeEquals(BaseType.OBJECT);
	
	output = new TypedIOPort(this, "output", false, true);
	output.setTypeEquals(BaseType.OBJECT);
	
	LS0Bytes = new Parameter(this, "LS0Bytes", new IntToken(8));	
	LS0Map = new Parameter(this, "LS0Map", new BooleanToken(false));
	
	S = new Parameter(this, "S", new IntToken(1));
    }

    ///////////////////////////////////////////////////////////////////
    ////                     ports and parameters                  ////
    
    public TypedIOPort start;
    public TypedIOPort dataTx;
    public TypedIOPort LS0;        
    public TypedIOPort output;
        
    public Parameter LS0Bytes;
    public Parameter LS0Map;    
    public Parameter S;    

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////
    
     public void attributeChanged(Attribute attribute)
            throws IllegalActionException {
        if(attribute == LS0Bytes) {
            IntToken it = (IntToken) LS0Bytes.getToken();
            _LS0Bytes = it.intValue();            
        }
        if(attribute == LS0Map) {
            BooleanToken bt = (BooleanToken) LS0Map.getToken();
	    _LS0Map = bt.booleanValue();   
        }
        else
        if(attribute == S) {
 	    IntToken it = (IntToken) S.getToken();
	    _S = it.intValue();           
        }
	else {
            super.attributeChanged(attribute);
        }                
    }
    
    public void initialize() throws IllegalActionException {
        super.initialize();			

        _checkParameters();
        
	_fastFrames = new LinkedList();
	_interFrames = new LinkedList();
	
	MuxDataFrame fastf = _newFastFrame();	
	_fastFrames.addLast(fastf);
	
	MuxDataFrame interf = _newInterFrame();
	_interFrames.addLast(interf);
		
	if(!_LS0Map) {
	    _currentLS0Frame = fastf;
	}
	else {
	    _currentLS0Frame = interf;
	}

	_LS0Wrote = 0;	
	_sentFrame = 0;	
	_mode = false;

        try {
	    File f = new File("ls0_r.tx");
	    FileOutputStream fo = new FileOutputStream(f);
	    _LS0_out = new DataOutputStream(fo);
	} catch(IOException ex) {
	    System.out.println(ex);
	}
	
    }
    
    public void fire() throws IllegalActionException {
	/*(if(start.hasToken(0)) {
	    BooleanToken bt = (BooleanToken) start.get(0);
	    _mode = bt.booleanValue();
	}*/
	_mode = true;
        
	if(_mode) {        
            _sendData();
	}
	else {
	    if(dataTx.hasToken(0)) dataTx.get(0);
	    if(LS0.hasToken(0)) LS0.get(0);
	}
    }

    public void wrapup() throws IllegalActionException {
        super.wrapup();
	try {
	    _LS0_out.close();
        } catch(IOException ex) {
	    System.out.println(ex);
	}
    }
    
    ///////////////////////////////////////////////////////////////////
    ////                         private methods                   ////

    private void _sendData() throws IllegalActionException {

        if(!dataTx.hasToken(0)) return;

        IntToken _it = (IntToken) dataTx.get(0);
	switch(_it.intValue()) {
	    case 0 : {
	        _ot = (ObjectToken) LS0.get(0);
	        Integer b = (Integer) _ot.getValue();
		
                try {
		    _LS0_out.write((byte) b.intValue());
		}
		catch(IOException ex) {
		    System.out.println(ex);
		}
		
	        if(_LS0Wrote == _LS0Bytes) {
	            _LS0Wrote = 0;
		    if(_LS0Map) {
		        _currentLS0Frame = _getNextInterFrame(_currentLS0Frame);
		    }
		    else {
		        _currentLS0Frame = _getNextFastFrame(_currentLS0Frame);
		    }
	        }
                _currentLS0Frame.setLS0Byte(b.intValue(), _LS0Wrote);
	        _LS0Wrote++;
	    } break;
	}
	
	_checkFullFrames();
    }

    private void _checkFullFrames() throws IllegalActionException {   	
	
	while(true) {
	    if(_sentFrame == 0) {
	        _mf = (MuxDataFrame) _fastFrames.get(0);
	        if(_currentLS0Frame != _mf) {
	            _fastFrames.remove(0);
		    _ot = new ObjectToken(_mf);		
		    output.broadcast(_ot);
		
		    _sentFrame = 1;
		    
		    if(_LS0Map) {
		        _mf = _newFastFrame();
			_fastFrames.addLast(_mf);
		    }
	        }
	        else {
	            return;
	        }
 	    }
	    else {
                _mf = (MuxDataFrame) _interFrames.get(0);
	        if(_currentLS0Frame != _mf) {
	            _interFrames.remove(0);
		    _ot = new ObjectToken(_mf);
		    output.broadcast(_ot);
		
		    _sentFrame++;
		    
		    if(!_LS0Map) {
		        _mf = _newInterFrame();
			_interFrames.addLast(_mf);
		    }
	        }
	        else {
	            return;
	        }
	    }
	    if(_sentFrame > _S) _sentFrame = 0;	
	}	
    }
    
    private MuxDataFrame _getNextFastFrame(MuxDataFrame frame) {        	
	int i = _fastFrames.indexOf(frame);
	
	if(i == _fastFrames.size() - 1) {
	    _mf = _newFastFrame();
	    _fastFrames.addLast(_mf);	    
	}
	else {
	    _mf = (MuxDataFrame) _fastFrames.get(i + 1);
	}
	
	return _mf;            
    }
    
    private MuxDataFrame _getNextInterFrame(MuxDataFrame frame) {	
	int i = _interFrames.indexOf(frame);
	
	if(i == _interFrames.size() - 1) {
	    _mf = _newInterFrame();
	    _interFrames.addLast(_mf);
	}
	else {
	    _mf = (MuxDataFrame) _interFrames.get(i + 1);
	}
	
	return _mf;
    }

    private MuxDataFrame _newFastFrame() {    
        _mf = new MuxDataFrame(0, 0, 0, 0, _LS0Map ? 0 : _LS0Bytes, 0, 0);
	  
	return _mf;
    }
    
    private MuxDataFrame _newInterFrame() {    
        _mf = new MuxDataFrame(0, 0, 0, 0, _LS0Map ? _LS0Bytes : 0, 0, 0);
	  
	return _mf;
    }
        
    private void _checkParameters() throws IllegalActionException {   	
	if(_LS0Bytes < 0) {
	    throw new IllegalActionException(this, "LS0 Bytes < 0");
	}
	
	if(_S != 1 && _S != 2 && _S != 4 && _S != 8 && _S != 16) {
	    throw new IllegalActionException(this, "\nInvalid value(" +
	        _S + ") for parameter S");
	}	
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private variables                 ////            

    private LinkedList _fastFrames;
    private LinkedList _interFrames;

    private ObjectToken _ot;
    private MuxDataFrame _mf;

    private int _sentFrame;
            
    private MuxDataFrame _currentLS0Frame;
    private int _LS0Wrote;

    private int _LS0Bytes;
    private boolean _LS0Map;
    private int _S;
    
    private boolean _mode;
    
    private DataOutputStream _LS0_out;
}
